package orm

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	"gorm.io/gorm/schema"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"sync"
	"time"
	"unicode"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Orm struct {
	db *gorm.DB
}

// orm模块配置
type OrmConfig struct {
	// 数据库配置路径
	dbConfig string
	// 数据结构文件所在目录
	domainDir string
	// 是否自动 AutoMigrateTables （上线后，这里要设置成false， 调试阶段可以设置为true）
	autoFlag bool
}

// 全局变量
var (
	once     sync.Once
	config   OrmConfig
	instance *Orm
)

// 反射类型映射（支持基础类型扩展）
var TypeMap = map[string]reflect.Type{
	"int":       reflect.TypeOf(0),
	"int32":     reflect.TypeOf(int32(0)),
	"int64":     reflect.TypeOf(int64(0)),
	"uint":      reflect.TypeOf(uint(0)),
	"uint32":    reflect.TypeOf(uint32(0)),
	"uint64":    reflect.TypeOf(uint64(0)),
	"string":    reflect.TypeOf(""),
	"bool":      reflect.TypeOf(false),
	"float32":   reflect.TypeOf(float32(0)),
	"float64":   reflect.TypeOf(float64(0)),
	"Time":      reflect.TypeOf(time.Time{}),      // time.Time类型
	"DeletedAt": reflect.TypeOf(gorm.DeletedAt{}), // gorm软删除
	"time.Time": reflect.TypeOf(time.Time{}),
	"Byte":      reflect.TypeOf(byte(0)),
	"rune":      reflect.TypeOf(rune(0)),
}

// FieldMeta 字段元数据
type FieldMeta struct {
	Name    string
	Type    reflect.Type
	GormTag string
	JsonTag string
}

// TableMeta 表元数据
type TableMeta struct {
	Name   string      // 表名（文件名）
	Fields []FieldMeta // 字段集合
}

// 初始化数据库和domain的配置
func InitConfig(host string, domainPath string, autoFlag bool) {
	config.dbConfig = host
	config.domainDir = domainPath
	config.autoFlag = autoFlag
}

// 获取orm实例
func GetInstance() *Orm {
	once.Do(func() {
		var err error
		// 这里假设使用MySQL数据库，根据实际情况修改DSN
		dsn := config.dbConfig
		instance = &Orm{}
		instance.db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
			NamingStrategy: schema.NamingStrategy{
				SingularTable: true, // 禁用表名复数化
			},
		})
		if err != nil {
			panic("数据库连接失败: " + err.Error())
		}
		if config.autoFlag {
			// 自动创建和更新表
			instance.AutoMigrateTables()
		}

	})
	return instance
}

// 自动创建和更新表
func (o *Orm) AutoMigrateTables() {
	// 遍历目录，闭包实现对每个文件的处理
	err := filepath.Walk(config.domainDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		//判断是否合法的go文件
		if !info.IsDir() && strings.HasSuffix(info.Name(), ".go") {
			// 解析文件元数据
			meta, err := o.parseFile(path)
			if err != nil {
				fmt.Printf("文件解析错误: %s (%v)\n", path, err)
				return nil
			}
			// 动态创建模型
			model := o.createDynamicModel(*meta)
			// 执行自动迁移
			err = o.db.Table(meta.Name).AutoMigrate(model)
			if err != nil {
				fmt.Printf("迁移失败 %s: %v\n", meta.Name, err)
			} else {
				fmt.Printf("成功迁移表: %s\n", meta.Name)
			}
		}
		return nil
	})
	if err != nil {
		panic("目录遍历错误: " + err.Error())
	}
}

// 解析AST类型到反射类型
func (o *Orm) parseExpr(expr ast.Expr) (reflect.Type, string) {
	switch t := expr.(type) {
	case *ast.Ident:
		if mapped, ok := TypeMap[t.Name]; ok {
			return mapped, t.Name
		}
		return reflect.TypeOf(new(interface{})).Elem(), t.Name
	case *ast.ArrayType:
		elemType, _ := o.parseExpr(t.Elt)
		return reflect.SliceOf(elemType), "array"
	case *ast.MapType:
		keyType, _ := o.parseExpr(t.Key)
		valueType, _ := o.parseExpr(t.Value)
		return reflect.MapOf(keyType, valueType), "map"
	case *ast.StructType:
		return reflect.TypeOf(new(interface{})).Elem(), "struct"
	case *ast.SelectorExpr:
		if x, ok := t.X.(*ast.Ident); ok && x.Name == "time" && t.Sel.Name == "Time" {
			return TypeMap["time.Time"], "time.Time"
		}
	}
	return reflect.TypeOf(new(interface{})).Elem(), "unknown"
}

// 解析结构体标签
func (o *Orm) parseTag(tag *ast.BasicLit) reflect.StructTag {
	if tag == nil {
		return ""
	}
	tagValue := strings.Trim(tag.Value, "`")
	return reflect.StructTag(tagValue)
}

// 解析GORM标签
func (o *Orm) buildGormTag(baseName string, typeName string, field *ast.Field) string {
	tags := []string{fmt.Sprintf("column:%s", baseName)}
	// 自动类型映射
	switch {
	case typeName == "time.Time":
		tags = append(tags, "type:datetime")
	case strings.HasPrefix(typeName, "array") ||
		strings.HasPrefix(typeName, "map") ||
		strings.HasPrefix(typeName, "struct"):
		//	需要高版本数据库支持json类型
		//tags = append(tags, "type:json")
		tags = append(tags, "type:longtext")
	}
	// 合并已有标签
	if field.Tag != nil {
		existing := strings.Trim(field.Tag.Value, "`")
		if gormTag := o.getTagValue(existing, "gorm"); gormTag != "" {
			tags = append(tags, gormTag)
		}
	}

	return strings.Join(tags, ";")
}

// getTagValue 从结构体标签字符串中获取指定tag的值
// 示例：getTagValue(`gorm:"primaryKey" json:"id"`, "gorm") -> "primaryKey"
func (o *Orm) getTagValue(tagString string, tagName string) string {
	// 分割所有tag项
	tags := strings.Split(strings.TrimSpace(tagString), " ")

	for _, tag := range tags {
		// 跳过空项
		if tag == "" {
			continue
		}

		// 分割键值对（最多分割2部分）
		parts := strings.SplitN(tag, ":", 2)
		if len(parts) < 2 {
			continue
		}

		// 对比tag名称（带大小写敏感）
		if strings.TrimSpace(parts[0]) != tagName {
			continue
		}

		// 去除值的引号
		value := strings.Trim(parts[1], `"`)
		return strings.TrimSpace(value)
	}
	return ""
}

// 解析文件获取表元数据
func (o *Orm) parseFile(path string) (*TableMeta, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
	if err != nil {
		return nil, err
	}
	// 获取表名称
	meta := &TableMeta{
		Name: strings.TrimSuffix(filepath.Base(path), ".go"),
	}
	// ast 语法树解析文件
	ast.Inspect(f, func(n ast.Node) bool {
		ts, ok := n.(*ast.TypeSpec)
		if !ok {
			return true
		}
		// 只处理文件内和表名一样的struct生成对应的表
		fmt.Printf("找到数据结构: %s\n", ts.Name.Name)
		structName := cases.Title(language.English).String(meta.Name)
		if ts.Name.Name != structName {
			return true
		}
		fmt.Printf("符合要求的数据结构: %v\n", structName)
		st, ok := ts.Type.(*ast.StructType)
		if !ok {
			return true
		}
		for _, field := range st.Fields.List {
			if len(field.Names) == 0 {
				continue // 跳过嵌入字段
			}
			//解析字段
			fieldType, typeName := o.parseExpr(field.Type)
			baseName := o.CamelToSnake(field.Names[0].Name)
			meta.Fields = append(meta.Fields, FieldMeta{
				Name:    baseName,
				Type:    fieldType,
				GormTag: o.buildGormTag(baseName, typeName, field),
			})
		}
		return false
	})

	return meta, nil
}

func (o *Orm) CamelToSnake(s string) string {
	var result []rune
	for i, r := range s {
		if unicode.IsUpper(r) {
			if i > 0 {
				// 检查前一个字符是否为小写
				if unicode.IsLower(rune(s[i-1])) {
					result = append(result, '_')
				}
				// 检查是否为连续大写字母的中间部分
				if i+1 < len(s) && unicode.IsUpper(rune(s[i+1])) {
					// 如果是连续大写字母，跳过下划线插入
					result = append(result, unicode.ToLower(r))
				} else {
					// 否则，正常插入下划线并转换为小写
					result = append(result, unicode.ToLower(r))
				}
			} else {
				// 如果是第一个字符，直接转换为小写
				result = append(result, unicode.ToLower(r))
			}
		} else {
			result = append(result, r)
		}
	}
	return strings.ToLower(string((result)))
}

// 动态创建GORM模型
func (o *Orm) createDynamicModel(meta TableMeta) interface{} {
	fields := make([]reflect.StructField, 0, len(meta.Fields))

	for _, f := range meta.Fields {
		fields = append(fields, reflect.StructField{
			Name: cases.Title(language.English).String(f.Name), // 首字母大写
			Type: f.Type,
			Tag:  reflect.StructTag(fmt.Sprintf(`gorm:"%s"`, f.GormTag)),
		})
	}

	modelType := reflect.StructOf(fields)
	fmt.Printf("动态创建数据结构: %v\n", modelType)
	return reflect.New(modelType).Interface()
}

func (o *Orm) Create(data interface{}) error {
	return o.db.Create(data).Error
}

// Read根据条件查询记录
func (o *Orm) Read(data interface{}, where ...interface{}) error {
	return o.db.Where(where).First(data).Error
}

// Update根据条件更新记录
func (o *Orm) Update(data interface{}, updates map[string]interface{}, where ...interface{}) error {
	return o.db.Model(data).Where(where).Updates(updates).Error
}

// Delete根据条件删除记录
func (o *Orm) Delete(data interface{}, where ...interface{}) error {
	return o.db.Where(where).Delete(data).Error
}
